style.scss 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. .user-profile {
  2. max-width: 720px;
  3. margin: 0 auto;
  4. padding: 0 16px 32px;
  5. &__header {
  6. display: flex;
  7. flex-direction: column;
  8. }
  9. // ── Banner (Bluesky 비율 3:1, ~200px) ──
  10. &__banner {
  11. aspect-ratio: 3 / 1;
  12. max-height: 200px;
  13. background: #dfdfdf;
  14. overflow: hidden;
  15. img {
  16. width: 100%;
  17. height: 100%;
  18. object-fit: cover;
  19. display: block;
  20. }
  21. }
  22. &__banner-placeholder {
  23. width: 100%;
  24. height: 100%;
  25. background: #dfdfdf;
  26. }
  27. // ── Identity row (avatar + actions) ──
  28. &__identity {
  29. display: flex;
  30. align-items: flex-start;
  31. justify-content: space-between;
  32. padding: 0 16px;
  33. margin-top: -48px;
  34. }
  35. &__avatar-wrap {
  36. position: relative;
  37. z-index: 2;
  38. }
  39. &__avatar {
  40. width: 96px;
  41. height: 96px;
  42. border-radius: 50%;
  43. overflow: hidden;
  44. border: 4px solid var(--bg-page, #fff);
  45. background: var(--bg-subtle, #f3f4f6);
  46. display: block;
  47. object-fit: cover;
  48. }
  49. &__avatar-fallback {
  50. width: 100%;
  51. height: 100%;
  52. display: flex;
  53. align-items: center;
  54. justify-content: center;
  55. font-weight: 700;
  56. font-size: 2rem;
  57. color: var(--text-muted);
  58. border-radius: 50%;
  59. }
  60. &__actions {
  61. display: flex;
  62. flex-wrap: wrap;
  63. align-items: center;
  64. gap: 6px;
  65. margin-top: 56px;
  66. }
  67. &__note-btn {
  68. display: inline-flex;
  69. align-items: center;
  70. justify-content: center;
  71. gap: 6px;
  72. padding: 6px 14px;
  73. border: 1px solid var(--border-default);
  74. border-radius: 999px;
  75. background: transparent;
  76. color: var(--fg-default);
  77. font-size: 0.875rem;
  78. font-weight: 600;
  79. cursor: pointer;
  80. transition: background-color 0.15s ease, border-color 0.15s ease;
  81. &:hover {
  82. background: var(--bg-subtle);
  83. border-color: var(--border-strong);
  84. }
  85. }
  86. &__edit-btn {
  87. display: inline-flex;
  88. align-items: center;
  89. justify-content: center;
  90. gap: 6px;
  91. padding: 6px 14px;
  92. border: 1px solid var(--border-default);
  93. border-radius: 999px;
  94. background: transparent;
  95. color: var(--fg-default);
  96. font-size: 0.875rem;
  97. font-weight: 600;
  98. cursor: pointer;
  99. transition: background-color 0.15s ease, border-color 0.15s ease;
  100. &:hover {
  101. background: var(--bg-subtle);
  102. border-color: var(--border-strong);
  103. }
  104. }
  105. &__more-btn {
  106. width: 36px;
  107. height: 36px;
  108. border-radius: 50%;
  109. border: 1px solid var(--border-default);
  110. background: transparent;
  111. color: var(--fg-default);
  112. cursor: pointer;
  113. display: inline-flex;
  114. align-items: center;
  115. justify-content: center;
  116. &:hover {
  117. background: var(--bg-subtle);
  118. }
  119. }
  120. // ── Info (name, handle, counts, bio) ──
  121. &__info {
  122. padding: 16px;
  123. display: flex;
  124. flex-direction: column;
  125. gap: 8px;
  126. }
  127. &__name {
  128. font-size: 1.5rem;
  129. font-weight: 800;
  130. display: flex;
  131. align-items: center;
  132. gap: 6px;
  133. line-height: 1.2;
  134. }
  135. &__badge {
  136. display: inline-flex;
  137. align-items: center;
  138. justify-content: center;
  139. &--creator {
  140. color: #3b82f6;
  141. }
  142. &--admin {
  143. color: #dc2626;
  144. }
  145. }
  146. &__handle {
  147. font-size: 0.9375rem;
  148. margin: 0;
  149. }
  150. &__handle-text {
  151. color: var(--text-muted);
  152. }
  153. &__handle-link {
  154. color: #8b5cf6;
  155. font-weight: 600;
  156. text-decoration: none;
  157. transition: color 0.15s ease;
  158. &:hover {
  159. color: #7c3aed;
  160. text-decoration: underline;
  161. }
  162. }
  163. &__counts {
  164. display: flex;
  165. flex-wrap: wrap;
  166. gap: 16px;
  167. font-size: 0.9375rem;
  168. color: var(--text-secondary, #4b5563);
  169. margin: 8px 0 0;
  170. strong {
  171. color: var(--fg-default);
  172. font-weight: 700;
  173. margin-right: 2px;
  174. }
  175. }
  176. &__counts-link {
  177. color: inherit;
  178. text-decoration: none;
  179. &:hover {
  180. text-decoration: underline;
  181. }
  182. }
  183. &__intro {
  184. margin: 6px 0 0;
  185. line-height: 1.55;
  186. color: var(--text-primary);
  187. white-space: pre-wrap;
  188. word-break: break-word;
  189. }
  190. // ── Stats card ──
  191. &__stats {
  192. display: grid;
  193. grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  194. gap: 12px;
  195. padding: 12px 16px;
  196. margin: 8px 0;
  197. border: 1px solid var(--border-default);
  198. border-radius: 12px;
  199. background: var(--bg-card, #fff);
  200. }
  201. &__stat {
  202. display: flex;
  203. align-items: center;
  204. gap: 10px;
  205. }
  206. &__stat-icon {
  207. flex-shrink: 0;
  208. &--coins {
  209. color: #f59e0b;
  210. }
  211. &--attendance {
  212. color: #22c55e;
  213. }
  214. &--streak {
  215. color: #f97316;
  216. }
  217. }
  218. &__stat-body {
  219. display: flex;
  220. flex-direction: column;
  221. }
  222. &__stat-label {
  223. font-size: 0.75rem;
  224. color: var(--text-muted);
  225. }
  226. &__stat-value {
  227. font-size: 1rem;
  228. font-weight: 700;
  229. color: var(--fg-default);
  230. }
  231. // ── Tabs ──
  232. &__tabs {
  233. display: flex;
  234. gap: 0;
  235. padding: 0 16px;
  236. border-bottom: 1px solid var(--border-default);
  237. margin-bottom: 12px;
  238. }
  239. &__tab {
  240. padding: 12px 20px;
  241. font-size: 0.9375rem;
  242. font-weight: 500;
  243. color: var(--text-muted);
  244. text-decoration: none;
  245. position: relative;
  246. &--active {
  247. color: var(--fg-default);
  248. font-weight: 700;
  249. &::after {
  250. content: '';
  251. position: absolute;
  252. bottom: -1px;
  253. left: 16px;
  254. right: 16px;
  255. height: 3px;
  256. background: #3b82f6;
  257. border-radius: 2px 2px 0 0;
  258. }
  259. }
  260. &:hover {
  261. color: var(--fg-default);
  262. }
  263. }
  264. &__content {
  265. padding: 0 16px;
  266. @media (max-width: 768px) {
  267. padding: 0;
  268. }
  269. }
  270. // ── Activity lists ──
  271. &__empty {
  272. text-align: center;
  273. color: var(--text-muted);
  274. padding: 40px 16px;
  275. font-size: 0.9375rem;
  276. }
  277. &__list {
  278. display: flex;
  279. flex-direction: column;
  280. gap: 8px;
  281. list-style: none;
  282. padding: 0;
  283. margin: 0;
  284. }
  285. &__list-item {
  286. border: 1px solid var(--border-default);
  287. border-radius: 12px;
  288. background: var(--bg-card, #fff);
  289. overflow: hidden;
  290. transition: border-color 0.15s ease;
  291. &:hover {
  292. border-color: var(--border-strong, #d1d5db);
  293. }
  294. }
  295. &__list-link {
  296. display: flex;
  297. gap: 12px;
  298. padding: 14px 16px;
  299. text-decoration: none;
  300. color: inherit;
  301. }
  302. &__list-thumb {
  303. width: 96px;
  304. height: 96px;
  305. object-fit: cover;
  306. border-radius: 8px;
  307. flex-shrink: 0;
  308. background: var(--bg-subtle);
  309. }
  310. &__list-body {
  311. flex: 1;
  312. min-width: 0;
  313. display: flex;
  314. flex-direction: column;
  315. gap: 4px;
  316. }
  317. &__list-meta {
  318. display: flex;
  319. align-items: center;
  320. gap: 4px;
  321. font-size: 0.8125rem;
  322. color: var(--text-muted);
  323. }
  324. &__list-board {
  325. font-weight: 600;
  326. color: var(--fg-default);
  327. }
  328. &__list-subject {
  329. font-size: 0.9375rem;
  330. font-weight: 600;
  331. color: var(--fg-default);
  332. margin: 0;
  333. overflow: hidden;
  334. text-overflow: ellipsis;
  335. display: -webkit-box;
  336. -webkit-line-clamp: 2;
  337. -webkit-box-orient: vertical;
  338. }
  339. &__list-comment {
  340. font-size: 0.875rem;
  341. color: var(--text-secondary, #4b5563);
  342. margin: 0;
  343. overflow: hidden;
  344. text-overflow: ellipsis;
  345. display: -webkit-box;
  346. -webkit-line-clamp: 2;
  347. -webkit-box-orient: vertical;
  348. }
  349. &__list-stats {
  350. display: flex;
  351. gap: 12px;
  352. font-size: 0.75rem;
  353. color: var(--text-muted);
  354. margin-top: 4px;
  355. }
  356. &__list-stat {
  357. display: inline-flex;
  358. align-items: center;
  359. gap: 4px;
  360. svg {
  361. flex-shrink: 0;
  362. }
  363. }
  364. &__list-author {
  365. display: flex;
  366. align-items: center;
  367. gap: 6px;
  368. margin-bottom: 6px;
  369. font-size: 0.8125rem;
  370. }
  371. &__list-author-avatar {
  372. width: 28px;
  373. height: 28px;
  374. border-radius: 50%;
  375. object-fit: cover;
  376. background: var(--bg-subtle, #f3f4f6);
  377. flex-shrink: 0;
  378. &--fallback {
  379. display: inline-flex;
  380. align-items: center;
  381. justify-content: center;
  382. font-weight: 700;
  383. color: var(--text-muted);
  384. font-size: 0.75rem;
  385. }
  386. }
  387. &__list-author-name {
  388. font-weight: 700;
  389. color: var(--fg-default);
  390. }
  391. &__list-author-handle {
  392. color: var(--text-muted);
  393. }
  394. &__list-parent {
  395. display: flex;
  396. align-items: center;
  397. flex-wrap: wrap;
  398. gap: 6px;
  399. font-size: 0.75rem;
  400. color: var(--text-muted);
  401. margin-top: 4px;
  402. padding: 6px 8px;
  403. background: var(--bg-subtle, #f3f4f6);
  404. border-radius: 6px;
  405. }
  406. &__list-parent-subject {
  407. color: var(--text-secondary, #4b5563);
  408. overflow: hidden;
  409. text-overflow: ellipsis;
  410. white-space: nowrap;
  411. flex: 1;
  412. min-width: 0;
  413. }
  414. // ── Edit dialog ──
  415. &__edit-dialog {
  416. max-width: 600px !important;
  417. width: calc(100vw - 32px);
  418. padding: 0 !important;
  419. gap: 0 !important;
  420. overflow: hidden;
  421. // DialogHeader (shadcn 첫 자식)
  422. > div:first-of-type {
  423. padding: 14px 20px;
  424. border-bottom: 1px solid var(--border-default);
  425. h2 {
  426. padding-bottom: 0;
  427. font-size: 1rem;
  428. font-weight: 700;
  429. color: var(--fg-default);
  430. }
  431. }
  432. }
  433. &__edit-body {
  434. display: flex;
  435. flex-direction: column;
  436. padding: 0 20px 20px;
  437. gap: 16px;
  438. }
  439. &__edit-banner {
  440. position: relative;
  441. aspect-ratio: 3 / 1;
  442. max-height: 180px;
  443. margin: 0 -20px;
  444. background: #dfdfdf;
  445. overflow: hidden;
  446. img {
  447. width: 100%;
  448. height: 100%;
  449. object-fit: cover;
  450. display: block;
  451. }
  452. }
  453. &__edit-banner-placeholder {
  454. width: 100%;
  455. height: 100%;
  456. }
  457. &__edit-banner-actions {
  458. position: absolute;
  459. right: 12px;
  460. bottom: 12px;
  461. display: flex;
  462. gap: 6px;
  463. }
  464. &__edit-banner-btn {
  465. width: 36px;
  466. height: 36px;
  467. border-radius: 50%;
  468. border: none;
  469. background: rgba(0, 0, 0, 0.55);
  470. color: #fff;
  471. cursor: pointer;
  472. display: inline-flex;
  473. align-items: center;
  474. justify-content: center;
  475. &:hover {
  476. background: rgba(0, 0, 0, 0.75);
  477. }
  478. }
  479. &__edit-avatar-wrap {
  480. position: relative;
  481. width: 80px;
  482. height: 80px;
  483. margin: -40px 0 0 8px;
  484. }
  485. &__edit-avatar {
  486. width: 80px;
  487. height: 80px;
  488. border-radius: 50%;
  489. object-fit: cover;
  490. border: 4px solid var(--bg-page, #fff);
  491. background: var(--bg-subtle);
  492. display: block;
  493. &--empty {
  494. display: flex;
  495. align-items: center;
  496. justify-content: center;
  497. background: var(--bg-subtle, #f3f4f6);
  498. color: var(--text-muted);
  499. }
  500. }
  501. &__edit-avatar-btn {
  502. position: absolute;
  503. right: -4px;
  504. bottom: -4px;
  505. width: 28px;
  506. height: 28px;
  507. border-radius: 50%;
  508. border: 2px solid var(--bg-page);
  509. background: #3b82f6;
  510. color: #fff;
  511. cursor: pointer;
  512. display: inline-flex;
  513. align-items: center;
  514. justify-content: center;
  515. &:hover {
  516. background: #2563eb;
  517. }
  518. }
  519. &__edit-fields {
  520. display: flex;
  521. flex-direction: column;
  522. gap: 14px;
  523. }
  524. &__edit-field {
  525. display: flex;
  526. flex-direction: column;
  527. gap: 6px;
  528. > span {
  529. font-size: 0.8125rem;
  530. font-weight: 600;
  531. color: var(--fg-default);
  532. }
  533. input[type="text"],
  534. textarea {
  535. padding: 8px 10px;
  536. border-radius: 8px;
  537. border: 1px solid var(--border-default);
  538. background: var(--bg-page);
  539. font-size: 0.9375rem;
  540. color: var(--fg-default);
  541. outline: none;
  542. font-family: inherit;
  543. &:focus {
  544. border-color: #3b82f6;
  545. }
  546. }
  547. textarea {
  548. resize: vertical;
  549. min-height: 100px;
  550. }
  551. }
  552. &__edit-error {
  553. color: #dc2626;
  554. font-size: 0.8125rem;
  555. margin: 0;
  556. }
  557. &__edit-footer {
  558. display: flex;
  559. justify-content: center;
  560. gap: 8px;
  561. padding-top: 4px;
  562. }
  563. &__edit-cancel,
  564. &__edit-save {
  565. padding: 8px 20px;
  566. border-radius: 4px;
  567. font-size: 0.875rem;
  568. font-weight: 600;
  569. cursor: pointer;
  570. }
  571. &__edit-cancel {
  572. background: transparent;
  573. color: var(--fg-default);
  574. border: 1px solid var(--border-default);
  575. &:hover {
  576. background: var(--bg-subtle);
  577. }
  578. }
  579. &__edit-save {
  580. background: #3b82f6;
  581. color: #fff;
  582. border: 1px solid #3b82f6;
  583. &:hover:not(:disabled) {
  584. background: #2563eb;
  585. border-color: #2563eb;
  586. }
  587. &:disabled {
  588. background: var(--bg-subtle);
  589. color: var(--text-muted);
  590. border-color: var(--bg-subtle);
  591. cursor: not-allowed;
  592. }
  593. }
  594. // ── Follow list (팔로워 / 팔로잉 페이지) ──
  595. &__subtab-title {
  596. font-size: 1.25rem;
  597. font-weight: 700;
  598. padding: 16px 16px 8px;
  599. margin: 0;
  600. color: var(--fg-default);
  601. }
  602. &__follow-section {
  603. display: flex;
  604. flex-direction: column;
  605. gap: 8px;
  606. }
  607. &__follow-total {
  608. font-size: 0.8125rem;
  609. color: var(--text-muted);
  610. margin: 0 0 4px;
  611. padding: 0 4px;
  612. }
  613. &__follow-list {
  614. list-style: none;
  615. padding: 0;
  616. margin: 0;
  617. display: flex;
  618. flex-direction: column;
  619. gap: 8px;
  620. }
  621. &__follow-item {
  622. display: flex;
  623. align-items: center;
  624. gap: 12px;
  625. padding: 14px 16px;
  626. border: 1px solid var(--border-default);
  627. border-radius: 12px;
  628. background: var(--bg-card, #fff);
  629. transition: border-color 0.15s ease;
  630. &:hover {
  631. border-color: var(--border-strong, #d1d5db);
  632. }
  633. }
  634. &__follow-avatar {
  635. width: 44px;
  636. height: 44px;
  637. border-radius: 50%;
  638. overflow: hidden;
  639. flex-shrink: 0;
  640. background: var(--bg-subtle, #f3f4f6);
  641. display: block;
  642. text-decoration: none;
  643. }
  644. &__follow-avatar-img {
  645. width: 100%;
  646. height: 100%;
  647. object-fit: cover;
  648. }
  649. &__follow-avatar-fallback {
  650. width: 100%;
  651. height: 100%;
  652. display: flex;
  653. align-items: center;
  654. justify-content: center;
  655. font-weight: 700;
  656. font-size: 1rem;
  657. color: var(--text-muted);
  658. }
  659. &__follow-body {
  660. flex: 1;
  661. min-width: 0;
  662. display: flex;
  663. flex-direction: column;
  664. gap: 2px;
  665. }
  666. &__follow-name {
  667. font-size: 0.9375rem;
  668. font-weight: 700;
  669. color: var(--fg-default);
  670. text-decoration: none;
  671. display: inline-flex;
  672. align-items: center;
  673. gap: 4px;
  674. &:hover .user-profile__follow-name-text {
  675. text-decoration: underline;
  676. }
  677. }
  678. &__follow-badge {
  679. display: inline-flex;
  680. align-items: center;
  681. justify-content: center;
  682. color: #3b82f6;
  683. }
  684. &__follow-handle {
  685. font-size: 0.8125rem;
  686. color: var(--text-muted);
  687. }
  688. &__follow-summary {
  689. font-size: 0.8125rem;
  690. color: var(--text-secondary, #4b5563);
  691. margin: 2px 0 0;
  692. line-height: 1.4;
  693. overflow: hidden;
  694. text-overflow: ellipsis;
  695. display: -webkit-box;
  696. -webkit-line-clamp: 2;
  697. -webkit-box-orient: vertical;
  698. }
  699. &__follow-btn {
  700. flex-shrink: 0;
  701. }
  702. &__follow-error {
  703. color: #dc2626;
  704. font-size: 0.8125rem;
  705. padding: 8px;
  706. text-align: center;
  707. }
  708. &__follow-more-btn {
  709. align-self: center;
  710. margin-top: 12px;
  711. padding: 8px 20px;
  712. border-radius: 999px;
  713. background: transparent;
  714. border: 1px solid var(--border-default);
  715. color: var(--text-secondary);
  716. font-size: 0.8125rem;
  717. cursor: pointer;
  718. &:hover:not(:disabled) {
  719. background: var(--bg-subtle);
  720. color: var(--fg-default);
  721. }
  722. &:disabled {
  723. opacity: 0.6;
  724. cursor: not-allowed;
  725. }
  726. }
  727. }